import { generateUUID } from '../../utils'
import { addReadyProduct, getReadyProduct } from '../core/ReadyProducts'
import { schedule } from '../core/Scheduler'
import { currentTime } from '../core/SimulationClock'
import { messageTransfer } from '../messaging/MessageTransfer'
import { randomTime } from '../types'
import BaseStation from './BaseStation'
import Product from './Product'

type SourceProductMap = Record<string, Product[]>
type RequiredInputMap = Record<string, number>

class AssemblyStation extends BaseStation {
  processTime: randomTime
  // 每个来源站点需要的产品数量
  requiredInputs: RequiredInputMap
  // 缓冲区按来源组织
  bufferMap: SourceProductMap = {}
  currentNewProduct: Product | null = null
  productWidth: number
  productHeight: number

  constructor(
    id: string,
    name: string,
    x: number,
    y: number,
    width = 100,
    height = 100,
    requiredInputs: RequiredInputMap,
    processTime: randomTime,
    productWidth: number = 20,
    productHeight: number = 20
  ) {
    super(id, name, x, y, width, height)
    this.requiredInputs = requiredInputs
    this.processTime = processTime
    this.productWidth = productWidth
    this.productHeight = productHeight
  }

  //判断是否可以接收上游传递的产品
  public canReceiveProduct(name: string): boolean {
    if (this.status !== 'idle') {
      return false
    }
    if (this.bufferMap[name] === undefined) {
      return true
    }
    if (this.bufferMap[name].length < this.requiredInputs[name]) {
      return true
    }
    return false
  }

  //接受就绪产品
  receiveReadyProduct(productId: string): void {
    if (this.status === 'idle') {
      this.readyProduct = productId
      const product = getReadyProduct(productId)
      if (!product) {
        console.log(`[${currentTime}] ❌ ${productId} 没有发现`)
        return
      }
      console.log(`[${currentTime}] ${product.id} 已到达 --> ${this.name}`)
      this.onProductReceived(product)
    } else {
      console.log(`[${currentTime}] ${this.name} 不在空闲状态，无法接收产品 ${productId}`)
    }
  }

  protected onProductReceived(product: Product): void {
    const source = product.from || 'unknown'
    product.setFrom(this.id)
    console.log(`[${currentTime}] ${product.id} 到达装配站 ${this.name}，来自 ${source}`)
    messageTransfer('product', 'move', { targetId: this.id, productId: product.id })

    // 将产品加入对应来源的缓存
    if (!this.bufferMap[source]) {
      this.bufferMap[source] = []
    }
    this.bufferMap[source].push(product)
    // 检查是否满足所有来源的数量要求
    this.tryAssemble()
  }

  //判断是否可以开始装配
  private canAssemble(): boolean {
    for (const [source, requiredCount] of Object.entries(this.requiredInputs)) {
      if (
        !this.bufferMap[source] ||
        this.bufferMap[source].length === 0 ||
        this.bufferMap[source].length < requiredCount
      ) {
        return false
      }
    }
    return true
  }

  private tryAssemble(): void {
    if (!this.canAssemble()) return
    this.setStatus('processing')

    const parts: Product[] = []
    for (const [source, count] of Object.entries(this.requiredInputs)) {
      const group = this.bufferMap[source].splice(0, count)
      parts.push(...group)
    }

    // 生成新的产品
    const newProduct = new Product(generateUUID(), this.productWidth, this.productHeight)
    this.currentNewProduct = newProduct
    messageTransfer('product', 'generate', { targetId: this.id, productId: newProduct.id })
    messageTransfer('product', 'startProcessing', { targetId: this.id, productId: newProduct.id })
    this.currentNewProduct = newProduct

    // 消除旧的产品
    for (const p of parts) {
      messageTransfer('product', 'recycle', {
        targetId: this.id,
        productId: p.id
      })
    }

    messageTransfer('product', 'startProcessing', {
      targetId: this.id,
      productId: newProduct.id
    })

    const time = typeof this.processTime === 'function' ? this.processTime() : this.processTime
    console.log(`[${currentTime}] 🛠️ ${this.name} 开始装配 ${newProduct.id}`)

    schedule(time, () => this.finishAssemble(newProduct), `${this.id} 完成装配 ${newProduct.id}`)
  }

  private finishAssemble(newProduct: Product): void {
    messageTransfer('product', 'finishProcessing', { targetId: this.id, productId: newProduct.id })
    //当前产品添加到就绪产品队列中
    addReadyProduct(newProduct)
    //产品加工完毕，尝试派发产品
    this.setStatus('block')
  }

  tryDispatchCurrentProduct(): void {
    if (!this.currentNewProduct) return
    const productId = this.currentNewProduct.id
    for (const next of this.nextStations) {
      if (next.canReceiveProduct(this.id, this.currentNewProduct)) {
        this.currentNewProduct = null
        next.receiveReadyProduct(productId)
        //清空缓冲区
        for (const key of Object.keys(this.bufferMap)) {
          this.bufferMap[key] = []
        }
        this.setStatus('idle')
        break
      }
    }
  }
}

export default AssemblyStation
